﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Media;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;

namespace InChatter.Client.Service
{
    public class ChatMsgCenter
    {
        private static Lazy<ChatMsgCenter> _Instance = new Lazy<ChatMsgCenter>();

        public static ChatMsgCenter Instance
        {
            get
            {
                return _Instance.Value;
            }
        }

        public string DbUrl { set; get; }

        private ChatServer.ChatClient Client { set; get; }

        private ChatCallback callback { set; get; }

        #region Event
        /// <summary>
        /// when receive a message
        /// </summary>
        public event Action<ChatServer.InChatterMessage> MessageReceived;
        /// <summary>
        /// when read a message
        /// </summary>
        public event Action<ChatServer.InChatterMessage> MessageRead;
        /// <summary>
        /// when message pool receive a new message
        /// </summary>
        public event Action<ChatServer.InChatterMessage> MessagePoolReceivedNew;
        /// <summary>
        /// When a client ignore the messages noticed
        /// </summary>
        public event Action<ChatServer.InChatterMessage> MessageIgnored;

        public event Action<string, string> TypeChanged;
        /// <summary>
        /// Client login
        /// </summary>
        public event Action<string> ClientLogin;
        /// <summary>
        /// Click message notice to read
        /// </summary>
        public event Action<IEnumerable<ChatServer.InChatterMessage>> RequestToRead;
        /// <summary>
        /// Two clients chat directly
        /// </summary>
        public Func<ChatServer.InChatterMessage, bool> MessageReadDirectly;
        /// <summary>
        /// Message count changed
        /// </summary>
        public event Action<int> MessageCountChanged;
        #endregion

        #region Event Handler
        public void OnMessageCountChanged(int count)
        {
            if (MessageCountChanged != null)
            {
                MessageCountChanged(count);
            }
        }
        public void OnMessagePoolReceivedNew(ChatServer.InChatterMessage msg)
        {
            if (MessagePoolReceivedNew != null)
            {
                MessagePoolReceivedNew(msg);
            }
        }
        /// <summary>
        /// when ignore a message
        /// </summary>
        /// <param name="item"></param>
        public void OnMessageIgnored(ChatServer.InChatterMessage item)
        {
            if (MessageIgnored != null)
            {
                MessageIgnored(item);
            }
        }
        /// <summary>
        /// when read a message
        /// </summary>
        /// <param name="msg"></param>
        public void OnMessageRead(ChatServer.InChatterMessage msg)
        {
            if (MessageRead != null)
            {
                MessageRead(msg);
            }
        }
        public void OnRequestToRead(IEnumerable<ChatServer.InChatterMessage> msg)
        {
            if (RequestToRead != null)
            {
                RequestToRead(msg);
            }
        }
        public bool OnMessageReadDirectly(ChatServer.InChatterMessage msg)
        {
            if (MessageReadDirectly != null)
            {
                return MessageReadDirectly(msg);
            }
            return false;
        }
        public void OnTypeChanged(string type, string id)
        {
            if (TypeChanged != null)
            {
                TypeChanged(type, id);
            }
        }
        public void OnClientLogin(string ids)
        {
            if (ClientLogin != null)
            {
                ClientLogin(ids);
            }
        }
        #endregion

        public ChatMsgCenter()
        {
            callback = new ChatCallback();
            Client = new ChatServer.ChatClient(new System.ServiceModel.InstanceContext(callback), "NetTcpBinding_IChat");
            callback.OnMessgeReceived += callback_OnMessgeReceived;
        }

        private void callback_OnMessgeReceived(ChatServer.InChatterMessage message)
        {

            if (message.Type == "notice" || message.Type == "msg")
            {
                DataHelper.Save(message);
                using (SoundPlayer player = new SoundPlayer(System.AppDomain.CurrentDomain.BaseDirectory + "Sounds\\" + message.Type + ".wav"))
                {
                    player.Play();
                }
            }
            else if (message.Type == "logon" || message.Type == "logoff")
            {
                using (SoundPlayer player = new SoundPlayer(System.AppDomain.CurrentDomain.BaseDirectory + "Sounds\\Global.wav"))
                {
                    player.Play();
                }
            }
            if (MessageReceived != null)
            {
                MessageReceived(message);
            }
        }

        public void Login()
        {
            DbUrl = "Messages\\" + ClientContext.Current.ClientId + ".db";
            try
            {
                bool isLogin = Client.Login(ClientContext.Current.ClientId);
                ClientContext.Current.IsOnline = true;
            }
            catch
            {

            }
        }

        public void SendMsg(ChatServer.InChatterMessage message)
        {
            DataHelper.Save(message);
            message.IsRead = false;
            Client.SendMsg(message);
        }

        public void Logout()
        {
            Client.Logout(ClientContext.Current.ClientId);
        }

        public List<ChatServer.InChatterMessage> ReadAllMessage()
        {
            if (string.IsNullOrEmpty(DbUrl))
            {
                return null;
            }
            lock (string.Intern(DbUrl))
            {
                //history message will be saved for 1 month
                using (var db = NDatabase.OdbFactory.Open(DbUrl))
                {
                    var result = db.QueryAndExecute<ChatServer.InChatterMessage>().Where(p => p.IsRead == true).ToList();
                    string timeStr = DateTime.Now.Date.AddMonths(-1).ToString("yyyy-MM-dd HH:mm:ss");
                    for (int i = 0; i < result.Count; i++)
                    {
                        if (result[i].SendTime.CompareTo(timeStr) < 0)
                        {
                            db.Delete(result[i]);
                            result.RemoveAt(i);
                            i--;
                        }
                    }
                    return result;
                }
            }
        }

        public void GetLocalUnReadMsg()
        {
            try
            {
                lock (string.Intern(DbUrl))
                {
                    using (var db = NDatabase.OdbFactory.Open(DbUrl))
                    {
                        var result = (from item in db.AsQueryable<ChatServer.InChatterMessage>()
                                      where item.IsRead == false
                                      select item).ToList().OrderBy(p => p.SendTime);
                        foreach (var msg in result)
                        {
                            if (MessageReceived != null)
                            {
                                MessageReceived(msg);
                            }
                        }
                    }
                }
            }
            catch
            {
                return;
            }
        }

        public void ReceiveLeaveMsg()
        {
            if (Client == null) { return; }
            try
            {
                Client.ReceiveLeaveMsg();
            }
            catch
            {

            }
        }

        public string GetOnlineClient()
        {
            if (Client == null) { return ""; }
            return Client.GetOnlineClient();
        }

        /// <summary>
        /// it should be called when the first client log in the system,and synchronous clients info to the server
        /// </summary>
        public void SynchronousAllClients()
        {
            if (Client == null) { return; }
            JavaScriptSerializer jss = new JavaScriptSerializer();
            Dictionary<string, string> dictionary = new Dictionary<string, string>();
            foreach (var item in ClientContext.AllClients)
            {
                if (!dictionary.ContainsKey(item.ClientId))
                {
                    dictionary.Add(item.ClientId, item.ClientName);
                }
            }
            string clients = jss.Serialize(dictionary);
            Client.SynchronousAllClients(clients);
        }

    }
}
